/***************************************************************************
* Copyright  Faraday Technology Corp 2002-2003.  All rights reserved.      *
*--------------------------------------------------------------------------*
* Name:DMA.c                                                               *
* Description: DMA C Library routine                                       *
* Author: Fred Chien                                                       *
****************************************************************************/
#include "DMA020.h"

//UINT32  dma_instance_N;
volatile fLib_DMA_Reg_st *fLib_DMA_Register = (fLib_DMA_Reg_st *)DMA_FTDMAC020_0_PA_BASE;

int fLib_IsDMAChannelBusy(INT32 Channel)
{
	return ((fLib_DMA_Register->dma_ch_busy >> Channel) & 0x1);
}

int fLib_IsDMAChannelEnable(INT32 Channel)
{
	return ((fLib_DMA_Register->dma_ch_enable >> Channel) & 0x1);
}

int fLib_GetDMABusyStatus(void)
{
        return fLib_DMA_Register->dma_ch_busy;
}

int fLib_GetDMAEnableStatus(void)
{
        return fLib_DMA_Register->dma_ch_enable;
}

UINT32 fLib_GetDMAIntStatus(void)
{
	return fLib_DMA_Register->dma_int;
}

UINT32 fLib_GetDMAChannelIntStatus(INT32 Channel)
{
	UINT32 IntStatus = 0;

	if((fLib_DMA_Register->dma_int >> Channel) & 0x01)
	{
		if((fLib_DMA_Register->dma_int_tc >> Channel) & 0x01)
			IntStatus |= 1;
		if((fLib_DMA_Register->dma_int_err >> Channel) & 0x01)
			IntStatus |= 2;
		// dma030 haven't
		if((fLib_DMA_Register->dma_int_err >> (Channel+16)) & 0x01)
			IntStatus |= 4;
		//
	}

	return IntStatus;
}
//only dma020 has
void fLib_InitDMA(UINT32 M0_BigEndian, UINT32 M1_BigEndian, UINT32 Sync)
{
	fLib_DMA_Register->dma_csr = (M0_BigEndian ? DMA_CSR_M0ENDIAN : 0) |
	(M1_BigEndian ? DMA_CSR_M1ENDIAN : 0) | DMA_CSR_DMACEN;

	fLib_DMA_Register->dma_sync = Sync;
}

void fLib_EnableDMAChannel(INT32 Channel)
{
	volatile UINT32 reg;

	reg = *(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr;
	reg |= DMA_CSR_CH_ENABLE;
	*(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr = reg;
}

void fLib_DisableDMAChannel(INT32 Channel)
{
	volatile UINT32 reg;

	reg = *(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr;
	reg &= ~DMA_CSR_CH_ENABLE;
	*(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr = reg;
}

// This function was modified by jerry
void fLib_ClearDMAChannelIntStatus(INT32 Channel)
{
	UINT32 ctrl;

	ctrl = 1 << Channel;
	fLib_DMA_Register->dma_int_tc_clr = ctrl;

	ctrl = (1<<Channel) | (1<<(Channel+16));
	fLib_DMA_Register->dma_int_err_clr = ctrl;

}
// only dma020 has
void fLib_AbortDMAChannel(INT32 Channel)
{
	volatile UINT32 reg;

	reg = *(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr;
	reg |= DMA_CSR_ABT;
	*(UINT32 *)&fLib_DMA_Register->dma_ch[Channel].csr = reg;
}
// only dma020 has
void fLib_SetDMAChannelCfg_HW_Handshake(INT32 Channel, UINT32 SRC_HE, UINT32 SRC_REQ, UINT32 DST_HE, UINT32 DST_REQ)
{
	fLib_DMA_CH_CFG_t tmp_cfg;
	
	tmp_cfg = fLib_DMA_Register->dma_ch[Channel].cfg;
	tmp_cfg.DST_EN = DST_HE;
	tmp_cfg.DST_RS = DST_REQ;
	tmp_cfg.SRC_HE = SRC_HE;
	tmp_cfg.SRC_RS = SRC_REQ;
	fLib_DMA_Register->dma_ch[Channel].cfg = tmp_cfg;
}

void fLib_SetDMAChannelCfg(INT32 Channel, fLib_DMA_CH_CSR_t Csr)
{
	fLib_DMA_Register->dma_ch[Channel].csr = Csr;
}

void fLib_SetDMAChannelCnCfg(INT32 Channel, fLib_DMA_CH_CFG_t CnCfg)
{
	fLib_DMA_Register->dma_ch[Channel].cfg = CnCfg;
}

fLib_DMA_CH_CSR_t fLib_GetDMAChannelCfg(INT32 Channel)
{
	return (fLib_DMA_Register->dma_ch[Channel].csr);
}

void fLib_DMA_CHIntMask(INT32 Channel, fLib_DMA_CH_CFG_t Mask)
{
	fLib_DMA_CH_CFG_t tmp_cfg;
	
	tmp_cfg = fLib_DMA_Register->dma_ch[Channel].cfg;
	tmp_cfg.int_tc_msk = Mask.int_tc_msk;
	tmp_cfg.int_err_msk = Mask.int_err_msk;
	tmp_cfg.int_abt_msk = Mask.int_abt_msk;
	fLib_DMA_Register->dma_ch[Channel].cfg = tmp_cfg;
}

void fLib_DMA_CHLinkList(INT32 Channel, fLib_DMA_CH_LLP_t LLP)
{
	fLib_DMA_Register->dma_ch[Channel].llp = LLP;
}

void fLib_DMA_CHDataCtrl(INT32 Channel, UINT32 SrcAddr, UINT32 DstAddr, UINT32 Size)
{
	fLib_DMA_Register->dma_ch[Channel].src_addr = SrcAddr;
	fLib_DMA_Register->dma_ch[Channel].dst_addr = DstAddr;
	fLib_DMA_Register->dma_ch[Channel].size = Size;
}

void fLib_DMA_SetInterrupt(UINT32 channel, UINT32 tcintr, UINT32 errintr, UINT32 abtintr)
{
	fLib_DMA_CH_CFG_t cfg;

	if(tcintr)
		cfg.int_tc_msk = 0;	// Enable terminal count interrupt
	else
		cfg.int_tc_msk = 1;	// Disable terminal count interrupt

	if(errintr)
		cfg.int_err_msk = 0;	// Enable error interrupt
	else
		cfg.int_err_msk = 1;	// Disable error interrupt

	if(abtintr)
		cfg.int_abt_msk = 0;	// Enable abort interrupt
	else
		cfg.int_abt_msk = 1;	// Disable abort interrupt

//	DMA_CHIntMask(channel, cfg);
	fLib_DMA_CHIntMask(channel, cfg);
}

void fLib_DMA_ResetChannel(UINT8 channel)
{
	UINT32 base = DMA_FTDMAC020_0_PA_BASE+DMA_CHANNEL0_BASE+channel*DMA_CHANNEL_OFFSET;

	outw((UINT32 *)(base+DMA_CHANNEL_CSR_OFFSET),0);
	outw((UINT32 *)(base+DMA_CHANNEL_CFG_OFFSET),7);
	outw((UINT32 *)(base+DMA_CHANNEL_SRCADDR_OFFSET),0);
	outw((UINT32 *)(base+DMA_CHANNEL_DSTADDR_OFFSET),0);
	outw((UINT32 *)(base+DMA_CHANNEL_LLP_OFFSET),0);
	outw((UINT32 *)(base+DMA_CHANNEL_SIZE_OFFSET),0);
}

void fLib_DMA_ClearAllInterrupt(void)
{
	// Clear all interrupt source
	outw((UINT32 *)(DMA_FTDMAC020_0_PA_BASE+DMA_INT_TC_CLR),0xFF);
	outw((UINT32 *)(DMA_FTDMAC020_0_PA_BASE+DMA_INT_ERRABT_CLR),0xFF00FF);
}


